package com.yaowk.sfp.common.db;

import com.yaowk.sfp.common.base.*;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.util.ObjectUtils;

import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public abstract class BaseServiceImpl<M extends BaseModel, E, ID extends Serializable> implements IBaseService<M, ID> {

    protected abstract BaseRepository getDao();

    public abstract E model2Entity(M model);

    public abstract M entity2Model(E entity);

    public abstract E updateParams(M model);

    public final static boolean isNotEmpty(Object obj) {
        return !ObjectUtils.isEmpty(obj);
    }

    public PageResp<M> page2pageResp(Page<E> page) {
        PageResp<M> pageResp = new PageResp<>();
        List<E> eList = page.getContent();
        List<M> mList = new ArrayList<>();
        pageResp.setList(mList);
        for (E e : eList) {
            mList.add(entity2Model(e));
        }
        pageResp.setPageNumber(page.getNumber() + 1);
        pageResp.setPageSize(page.getSize());
        pageResp.setTotalPage(page.getTotalPages());
        pageResp.setTotalRow(page.getTotalElements());
        return pageResp;
    }

    public List<M> entity2Model(Collection<E> list) {
        List<M> mList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (E e : list) {
                mList.add(entity2Model(e));
            }
        }
        return mList;
    }

    @Override
    @Transactional
    public M add(M model) {
        if (!model.isNew()) {
            throw new BaseException("this method can only add entity");
        }
        E entity = model2Entity(model);
        getDao().save(entity);
        return entity2Model(entity);
    }

    @Override
    @Transactional
    public M save(M model) {
        if (model.isNew()) {
            model = add(model);
        } else {
            model = update(model);
        }
        return model;
    }

    @Override
    @Transactional
    public M update(M model) {
        if (model.isNew()) {
            throw new BaseException("this method can only update entity");
        }
        E entity = updateParams(model);
        getDao().save(entity);
        return entity2Model(entity);
    }

    @Override
    public void deleteById(ID id) {
        getDao().delete(id);
    }

    @Override
    public void delete(M model) {
        getDao().delete(Example.of(model2Entity(model)));
    }

    @Override
    public M findById(ID id) {
        return entity2Model((E) getDao().findOne(id));
    }

    @Override
    public M findOne(M model) {
        return entity2Model((E) getDao().findOne(Example.of(model2Entity(model))));
    }

    @Override
    public List<M> findAll() {
        return entity2Model(getDao().findAll());
    }

    @Override
    public List<M> findAll(M model) {
        return entity2Model(getDao().findAll(Example.of(model2Entity(model))));
    }

    @Override
    public PageResp<M> findAll(PageReq pageReq) {
        PageRequest pageRequest = new PageRequest(pageReq.getPageNumber() - 1, pageReq.getPageSize(), new Sort(Sort.Direction.DESC, "id"));
        Page<E> page = getDao().findAll(pageRequest);
        return page2pageResp(page);
    }

    @Override
    public PageResp<M> findAll(M model, PageReq pageReq) {
        PageRequest pageRequest = new PageRequest(pageReq.getPageNumber() - 1, pageReq.getPageSize(), new Sort(Sort.Direction.DESC, "id"));
        Page<E> page = getDao().findAll(Example.of(model2Entity(model)), pageRequest);
        return page2pageResp(page);
    }
}
